#include "Mod3Algorithm.h"
#include <iostream>

//init algorithm
void Mod3Algorithm::Initialize(BattleShipPtr _battle)
{
	m_battle = _battle;
	m_maxLength = Ship::GetLength(Ship::AIRCRAFT);
	m_minLength = Ship::GetLength(Ship::DESTROYER);
	m_addStep = 0;
	for (int i = Ship::DESTROYER; i<= Ship::AIRCRAFT; i++)
		m_foundShip[i] = false;
	m_checkPoint.clear();
	m_pendingPoint.clear();
	AddMorePoint();
}//end

//found a pos
void Mod3Algorithm::FoundPos(Point p, bool value)
{
	//clear from checkPoint
	PointArray::iterator ii;
	for (ii=m_checkPoint.begin();ii!=m_checkPoint.end();ii++)
	{
		if (*ii == p)
		{
			break;
		}
	}
	if (ii != m_checkPoint.end())
	{
		m_checkPoint.erase(ii);
	}

	// remove from pending point
	for (ii = m_pendingPoint.begin(); ii != m_pendingPoint.end(); ii++)
	{
		if (*ii == p)
		{
			break;
		}
	}

	if (ii != m_pendingPoint.end())
	{
		m_pendingPoint.erase(ii);
	}
	//endl
	m_battle->SetValue(p,value);
}
//end

//found a ship
void Mod3Algorithm::FoundShip(ShipPtr ship)
{
	m_foundShip[ship->GetType()] = true;
	//recheck m_maxLength
	for (int i=Ship::AIRCRAFT; i >= Ship::DESTROYER;i--)
	{
		if (!m_foundShip[i])
		{
			m_maxLength = Ship::GetLength((Ship::TypeOfShip)i);
			break;
		}
	}

	//recheck m_minLength
	for (int i=Ship::DESTROYER; i <= Ship::AIRCRAFT;i++)
	{
		if (!m_foundShip[i])
		{
			m_minLength = Ship::GetLength((Ship::TypeOfShip)i);
			break;
		}
	}

	//check if found 5, then add more point
	if (m_maxLength < 5 && m_addStep < 2)
	{
		AddMorePoint();
	}
}//end


//clean up before guess pos
void Mod3Algorithm::CleanUp()
{
	PointArray toRemove;
	for (int i = 0; i < MAX_H; i++)
	for (int j = 0; j < MAX_V; j++)
	if (m_battle->IsUnkown(Point(i,j)))
	{
		Point top,bottom,left,right;
	
		top.second = bottom.second = j;
		top.first = i - 1;
		bottom.first = i + 1;

		left.first = right.first = i;
		left.second = j - 1;
		right.second = j + 1;		
		//check top;
		while (m_battle->IsUnkown(top))
		{
			top.first--;
		}
		//check bottom;
		while (m_battle->IsUnkown(bottom))
		{
			bottom.first++;
		}
		//check left
		while (m_battle->IsUnkown(left))
		{
			left.second --;
		}
		//check right
		while (m_battle->IsUnkown(right))
		{
			right.second ++;
		}
		if ((bottom.first - top.first - 1) < m_minLength
			&& (right.second - left.second -1 ) < m_minLength)
		{
			toRemove.push_back(Point(i,j));
#if ENABLE_LOG	
			std::cout << "remove point: "<<i<<":"<<j<<std::endl;
#endif
		}
	}

	PointArray::iterator ii;
	for (ii = toRemove.begin(); ii!=toRemove.end(); ii++)
	{
		FoundPos(*ii,false);
	}
}//end

//recheck
void Mod3Algorithm::RecheckPoint()
{
	PointArray::iterator ii;
	PointArray newCheck,newPending;
	for (ii = m_checkPoint.begin(); ii != m_checkPoint.end(); ii++)
	{
		if (m_battle->IsExist(*ii,m_maxLength))
		{
			newCheck.push_back(*ii);
		}
		else
		{
			newPending.push_back(*ii);
		}
	}

	for (ii = m_pendingPoint.begin(); ii != m_pendingPoint.end(); ii++)
	{
		if (m_battle->IsExist(*ii,m_maxLength))
		{
			newCheck.push_back(*ii);
		}
		else
		{
			newPending.push_back(*ii);
		}
	}
	m_checkPoint = newCheck;
	m_pendingPoint = newPending;
#if ENABLE_LOG
	if (m_pendingPoint.size() > 0)
	{
		std::cout << "Pending size: " << m_pendingPoint.size() << std::endl;
	}
#endif
}//end

//guess a point
Point Mod3Algorithm::GuessPos()
{
	Point result;
	CleanUp();
	RecheckPoint();

	if (m_checkPoint.size() == 0)
	{
		AddMorePoint();
	}

	int i = rand() % m_checkPoint.size();
	result = m_checkPoint[i];

	return result;
}//end

void Mod3Algorithm::AddMorePoint()
{
	if (m_addStep == 0)
	{
		//add point
		for (int i=0;i<MAX_H;i++)
		for (int j=0;j<MAX_V;j++)
		{
			if ((i+j) % 6 == 4)
			{
				#if ENABLE_LOG	
				std::cout << "p:" << i <<":"<<j<<std::endl;
				#endif
				AddPoint(Point(i,j));
			}
		}
	}
	else if (m_addStep == 1)
	{
		#if ENABLE_LOG	
		std::cout << "Add point for finding 3" << std::endl;
		#endif
		for (int i=0;i<MAX_H;i++)
		for (int j=0;j<MAX_V;j++)
		{
			if ((i + j) % 6 == 1 &&  m_battle->IsUnkown(Point(i,j)))
			{
				#if ENABLE_LOG	
				std::cout << "p:" << i <<":"<<j<<std::endl;
				#endif
				AddPoint(Point(i,j));
			}
		}
	}
	else if (m_addStep == 2)
	{
		//old style
		for (int i=0;i<MAX_H;i++)
		for (int j=0;j<MAX_V;j++)
		{
			if ((i + j) % 3 == 2 &&  m_battle->IsUnkown(Point(i,j)))
			{
				#if ENABLE_LOG	
				std::cout << "p:" << i <<":"<<j<<std::endl;
				#endif
				AddPoint(Point(i,j));
			}
		}
		#if ENABLE_LOG	
		std::cout << "size:" << m_checkPoint.size() << std::endl;
		#endif

	}

	m_addStep++;
}

//add a point to queue
void Mod3Algorithm::AddPoint(Point p)
{
	if (m_battle->IsExist(p,m_maxLength))
	{
		m_checkPoint.push_back(p);
	}
	else
	{
		m_pendingPoint.push_back(p);
	}
}//end

//guess direction
Point Mod3Algorithm::GuessDirection(Point lastP, Ship::Rotation& direction)
{
	Point result;
	for (int i=0 ; i < 4 ; i++)
	{
		Point newP;
		newP.first = lastP.first + s_dx[i];
		newP.second = lastP.second + s_dy[i];
		if (m_battle->IsUnkown(newP))
		{
			//simple first, optimize later
			if (i==1 || i==3)
			{
				direction = Ship::VERTICAL;
			}
			else
			{
				direction = Ship::HORIZONTAL;
			}

			if (m_battle->IsExist(lastP,direction,m_minLength))
			{
				result = newP;
				break;
			}
			else
			{
				std::cout << "We found this is impossible" <<std::endl;
			}
		}
	}
	return result;
}